# F:\桌面\bishe\bishe_back\bishe_back\src\main\resources\static\recommend_novels.py
import math
import pandas as pd
import numpy as np
from datetime import datetime
from sklearn.preprocessing import MinMaxScaler
import sys
import json

# 从命令行参数获取数据
userId = int(sys.argv[1])
dfNovelFile = sys.argv[2]
dfNovelTypeFile = sys.argv[3]
dfReadingHistoryFile = sys.argv[4]

# 从文件中读取JSON数据
with open(dfNovelFile, 'r',encoding='utf-8') as f:
    df_novel = pd.DataFrame(json.load(f))

with open(dfNovelTypeFile, 'r',encoding='utf-8') as f:
    df_novel_type = pd.DataFrame(json.load(f))

with open(dfReadingHistoryFile, 'r',encoding='utf-8') as f:
    df_reading_history = pd.DataFrame(json.load(f))
if not df_reading_history.empty:
    df_reading_history['lastReadTime'] = pd.to_datetime(df_reading_history['lastReadTime'])


# 合并小说类型数据到小说表
df_novel = pd.merge(df_novel, df_novel_type, left_on='id', right_on='novelId', how='left')

# 处理一对多关系，将小说类型合并为一个列表
df_novel = df_novel.groupby('id_x').agg({
    'hot': 'first',
    'boyOrGirl': 'first',
    'watchNum': 'first',
    'collectNum': 'first',
    'sort': 'first',
    'value': lambda x: list(x)
}).reset_index()


# 计算类型相似度得分
def calculate_type_similarity(novel_i_types, novel_j_types):
    common_types = set(novel_i_types) & set(novel_j_types)
    total_types = set(novel_i_types) | set(novel_j_types)
    if not total_types:
        return 0
    return len(common_types) / len(total_types)

# 计算数值特征得分，数值越高越好
def calculate_numeric_score(novel, numeric_features):
    scaler = MinMaxScaler()
    scaled = scaler.fit_transform(novel[numeric_features])
    # 数值越高得分越高
    score = np.sum(scaled) / len(numeric_features)
    return score

# 基于用户短期兴趣的推荐函数
def recommend_novels_short_term(user_id, df_novel, df_reading_history):
    if df_reading_history.empty:
        # 若用户没有阅读历史，按数值得分排序返回
        numeric_features = ['hot', 'watchNum', 'collectNum']
        novel_scores = {}
        novel_id_list = df_novel['id_x'].tolist()
        for novel_id in novel_id_list:
            novel = df_novel[df_novel['id_x'] == novel_id]
            numeric_score = calculate_numeric_score(novel, numeric_features)
            novel_scores[novel_id] = numeric_score
        sorted_scores = sorted(novel_scores.items(), key=lambda x: x[1], reverse=True)
        return [score[0] for score in sorted_scores]
    user_read = df_reading_history[df_reading_history['userId'] == user_id]
    novel_scores = {}
    novel_id_list = df_novel['id_x'].tolist()
    numeric_features = ['hot', 'watchNum', 'collectNum']
    now = datetime.now()

    for _, read_record in user_read.iterrows():
        read_novel_id = read_record['novelId']
        read_novel = df_novel[df_novel['id_x'] == read_novel_id]
        read_novel_types = read_novel['value'].values[0]
        last_read_time = read_record['lastReadTime']

        # 计算时间权重，阅读时间越近，权重越高
        time_weight = math.sqrt(1 / ((now - last_read_time).days + 1))

        # 计算数值特征得分
        numeric_score = calculate_numeric_score(read_novel, numeric_features)
        for novel_id in novel_id_list:
            if novel_id not in user_read['novelId'].tolist():
                novel = df_novel[df_novel['id_x'] == novel_id]
                novel_types = novel['value'].values[0]

                type_similarity = calculate_type_similarity(read_novel_types, novel_types)

                # 综合得分，可调整权重
                combined_score = 0.5 * type_similarity + 0.5 * numeric_score

                # 考虑时间权重
                weighted_score = combined_score * time_weight

                if novel_id not in novel_scores:
                    novel_scores[novel_id] = 0
                novel_scores[novel_id] += weighted_score

    sorted_scores = sorted(novel_scores.items(), key=lambda x: x[1], reverse=True)
    return [score[0] for score in sorted_scores]


# 为指定用户推荐小说
def recommend(user_id):
    recommended_novels = recommend_novels_short_term(user_id, df_novel, df_reading_history)
    return recommended_novels

result = recommend(userId)
print(result)
